package org.tim.protocol;

import com.google.common.collect.Lists;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.tim.spi.Protocol;
import org.tio.core.ChannelContext;
import org.tio.core.TioConfig;
import org.tio.core.exception.TioDecodeException;
import org.tio.core.intf.Packet;
import org.tio.server.intf.ServerAioHandler;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;

public class ServerAioHandlerHandler implements ServerAioHandler {
    @Autowired
    private ConfigurableApplicationContext applicationContext;

    public Packet decode(ByteBuffer byteBuffer, int i, int i1, int i2, ChannelContext channelContext) throws TioDecodeException {
        Iterator<Protocol> iterator = getProtocolAspects().stream().filter(protocol -> {
            return protocol.support(byteBuffer, i, i1, i2, channelContext);
        }).iterator();

        if (iterator.hasNext()) {
            var next = iterator.next();
            return next.decode(byteBuffer, i, i1, i2, channelContext);
        }else {
            throw new UnsupportedOperationException();
        }
    }

    public ByteBuffer encode(Packet packet, TioConfig tioConfig, ChannelContext channelContext) {
        var iterator = getProtocolAspects().stream().filter(protocol -> {
            return protocol.support(channelContext);
        }).iterator();

        if(iterator.hasNext()) {
            var next = iterator.next();
            return next.encode(packet, tioConfig, channelContext);
        }else {
            throw new UnsupportedOperationException();
        }
    }

    public void handler(Packet packet, ChannelContext channelContext) throws Exception {
        Iterator<Protocol> iterator = getProtocolAspects().stream().filter(protocol -> {
            return protocol.support(channelContext);
        }).iterator();

        if(iterator.hasNext()) {
            var next = iterator.next();
            next.handler(packet, channelContext);
        }else {
            throw new UnsupportedOperationException();
        }
    }

    private ArrayList<Protocol> getProtocolAspects(){
        var list = Lists.newArrayList(applicationContext.getBeanFactory().getBeanProvider(Protocol.class));
        AnnotationAwareOrderComparator.sort(list);
        return list;
    }
}
